﻿#pragma once
#include <angelscript.h>

_NAMESPACE_BEGIN

class AngelScriptBinder
{
public:
	SINGLETON_HELPER(AngelScriptBinder)

	AngelScriptBinder();

	virtual ~AngelScriptBinder();

	asIScriptEngine* GetEngine(){return this->engine;}	///得到脚本引擎

	int CompileMainScript(const char* file);

	int CompileScript(CONST_REF(string) module,CONST_REF(string) file);

	int LoadCompiledScript(CONST_REF(string) module,CONST_REF(string) file);

	void BindAllImportedFunctions(CONST_REF(string) module);

	///运行主脚本
	DWORD RunMainFunc();

	///得到主脚本上下文,上下文类似一个脚本的线程，可以暂停和继续
	asIScriptContext *GetVavailableContext();

	void RunScriptFunction(asIScriptObject* pthis,const char* decl,int paramnum,... );

protected:
	void MessageCallback(const asSMessageInfo *msg);	///脚本消息回调函数，负责输出脚本信息

	void print(const char *format, ...);

	void PrintVariables(asIScriptContext *ctx, int stackLevel);

	void ExceptionCallback(asIScriptContext *ctx);		///脚本出异常时的回调，负责输出异常信息

	static void pause();

	static void AsAssert(bool b);

	asIScriptEngine *engine;	///脚本引擎

	asIScriptContext *mainctx;	///主上下文 上下文可以有多个

	std::vector<asIScriptContext*> contexts;
};

class ASEvent
{
public:
	ASEvent();
	virtual   ~ASEvent(){} 
	///设置脚本中的事件响应函数
	/**@param pthis 调用函数的对象	@param func 响应函数的名称
	*/
	void SetHandler(asIScriptObject *pthis,CONST_REF(string) func);
	///触发无参数的事件
	void operator()()
	{
		if(!pcaller) return;
		Prepare();
		Execute();
	}
	void operator()(void* p1)
	{
		if(!pcaller) return;
		Prepare();
		int r=ctx->SetArgObject(0,(void*)p1);	assert(r>=0);
		Execute();
	}
	void operator()(void* p1,void* p2)
	{
		if(!pcaller) return;
		Prepare();
		int r=ctx->SetArgObject(0,(void*)p1);	assert(r>=0);
		r=ctx->SetArgObject(1,(void*)p2);	assert(r>=0);
		Execute();
	}
	void call()
	{
		if(!pcaller) return;
		Prepare();			
		Execute();
	}

	void call(int p1)
	{
		if(!pcaller) return;
		Prepare();
		int r=ctx->SetArgObject(0,(void*)&p1);	assert(r>=0);
		Execute();
	}
	void call(int p1,int p2)
	{
		if(!pcaller) return;
		Prepare();
		int r=ctx->SetArgObject(0,(void*)&p1);	assert(r>=0);
		r=ctx->SetArgObject(1,(void*)&p2);	assert(r>=0);
		Execute();
	}
	///调用脚本函数前的准备工作
	void Prepare();
	///执行脚本函数
	void Execute();
	///调用函数的对象
	asIScriptObject* pcaller;
	int funcID;///<响应函数的名称
	asIScriptContext *ctx;
	string funName;

protected:
};

//把脚本的文件保存到二进制流文件，继承asIBinaryStream接口
class CBytecodeStream : public asIBinaryStream
{
public:
	CBytecodeStream(const char *name) 
	{
		this->name = name; 
		this->name += ".bin";
		f = 0; 
		isReading = false;
	}

	~CBytecodeStream()
	{
		if( f )
			fclose(f); 
	}

	void Write(const void *ptr, asUINT size) 
	{
		if( size == 0 ) return; 
		if( f == 0 || isReading ) 
		{ 
			if( f ) 
				fclose(f); 
			f = fopen(name.c_str(), "wb"); 
			isReading = false;
		} 
		fwrite(ptr, size, 1, f); 
	}

	void Read(void *ptr, asUINT size) 
	{ 
		if( size == 0 ) return; 
		if( f == 0 || !isReading ) 
		{ 
			if( f ) 
				fclose(f); 
			f = fopen(name.c_str(), "rb");
			isReading = true;
		} 
		fread(ptr, size, 1, f); 
	}

	void Restart() 
	{
		if( f ) 
			fseek(f, 0, SEEK_SET);
	}

protected:
	std::string name;
	FILE *f;
	bool isReading;
};

///构造一个对象,脚本用
template<typename T>
void Constructor(T* o) {
	new(o) T();
}

///析构一个对象，脚本用
template<typename T>
void Destructor(T* o) {
	o->~T();
}

///对象的工厂方法,脚本用
template<typename T>
T* FactoryBehave(T) {
	return new T();
}


///空函数
static void dumy(){}

template<typename A,typename B>
B* refCast(A* a)
{
	//return dynamic_cast<B*>(a);		
	return (B*)(a);
}

template<typename A,typename B>
const B* valueCast(const A& a)
{
	//return dynamic_cast<const B*>(&a);		
	return (const B*)(&a);
}

#define DECLARE_CONSTRUCTOR(T)	r = engine->RegisterObjectBehaviour(#T, asBEHAVE_CONSTRUCT,"void f()",asFUNCTION(Constructor<T>),asCALL_CDECL_OBJLAST); assert( r >= 0 );

#define DECLARE_DERIVE(Son,Base)\
{r = engine->RegisterObjectBehaviour(#Son,asBEHAVE_IMPLICIT_REF_CAST,(string(#Base)+"@ f()").c_str(), asFUNCTION((refCast<Son,Base>)), asCALL_CDECL_OBJLAST);assert( r >= 0 );\
	r = engine->RegisterObjectBehaviour(#Base,asBEHAVE_REF_CAST,(string(#Son)+"@ f()").c_str(), asFUNCTION((refCast<Base,Son>)), asCALL_CDECL_OBJLAST); assert( r >= 0 );}

#define DECLARE_VALUE_DERIVE(Son,Base)\
{string sign1=string(#Base)+" @f(const "+#Son+" &in)";\
	r = engine->RegisterObjectBehaviour(#Base, asBEHAVE_FACTORY,sign1.c_str(),asFUNCTION((valueCast<Son,Base>)), asCALL_CDECL); assert( r >= 0 );}


#define DECLARE_EMPTY_ADD_RELEASE_REF(obj)\
	r = engine->RegisterObjectBehaviour(#obj, asBEHAVE_ADDREF, "void f()", asFUNCTION(dumy), asCALL_CDECL_OBJLAST);assert( r >= 0 );\
	r = engine->RegisterObjectBehaviour(#obj, asBEHAVE_RELEASE, "void f()", asFUNCTION(dumy), asCALL_CDECL_OBJLAST);assert( r >= 0 );

#define MACRO_TOSTR(v) #v
#define DELARE_FACTORY_ADD_RELEASE(type)\
	r=engine->RegisterObjectBehaviour(#type, asBEHAVE_FACTORY,MACRO_TOSTR(type##@f()),asFUNCTIONPR(FactoryBehave,(type),type*),asCALL_CDECL_OBJLAST);	assert( r >= 0 );\
	r=engine->RegisterObjectBehaviour(#type, asBEHAVE_RELEASE, "void f()", asMETHOD(type, Ref_Release), asCALL_THISCALL);	assert( r >= 0 );\
	r=engine->RegisterObjectBehaviour(#type, asBEHAVE_ADDREF, "void f()", asMETHOD(type, Ref_AddRef), asCALL_THISCALL);	assert( r >= 0 );

#define BASEMETHODS(Tname,T,Base)	Register_##Base##_Methods<T>(engine,0,Tname);
#define TYPEMETHODS(T) BASEMETHODS(#T,T,T)
#define REGISTER_TYPEMETHODS(TYPE)\
	template<typename T>\
	void Register_##TYPE##_Methods(asIScriptEngine* engine,int r,const char* type)	

template<typename T>
T* New_Type(){return new T();}

_NAMESPACE_END